package com.alpha.runes.util;

import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.RequiresApi;

import org.apache.commons.codec.binary.Hex;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * AES加密工具类
 *
 * @author ACGkaka
 * @since 2021-06-18 19:11:03
 */
public class AESUtil {
    /**
     * 日志相关
     */
//    private static final Logger LOGGER = LoggerFactory.getLogger(AESUtil.class);
    /**
     * 编码
     */
    private static final String ENCODING = "UTF-8";
    /**
     * 算法定义
     */
    private static final String AES_ALGORITHM = "AES";
    /**
     * 指定填充方式
     */
    private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding";
    private static final String CIPHER_CBC_PADDING = "AES/CBC/NOPadding";
    /**
     * 偏移量(CBC中使用，增强加密算法强度)
     */
    private static final String IV_SEED = "1234567812345";

    private static final String KEY = "zx39i8y92snxk110";


    private static final byte[] CBC_KEY = {0x76, 0x49, (byte) 0xab, (byte) 0xac, (byte) 0x81, 0x19, (byte) 0xb2, 0x46, (byte) 0xce, (byte) 0xe9, (byte) 0x8e, (byte) 0x9b, 0x12, (byte) 0xe9, 0x19, 0x7d};
    private static final byte[] CBC_IV = {0x73, (byte) 0xbe, (byte) 0xd6, (byte) 0xb8, (byte) 0xe3, (byte) 0xc1, 0x74, 0x3b, 0x71, 0x16, (byte) 0xe6, (byte) 0x9e, 0x22, 0x22, (byte) 0x95, 0x16};


    /**
     * AES加密
     *
     * @param content 待加密内容
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encrypt(String content) {
        if (!TextUtils.isEmpty(content)) {
            Log.e("", "AES encrypt: the content is null!");
            return null;
        }
        //判断秘钥是否为16位
        try {
            //对密码进行编码
            byte[] bytes = KEY.getBytes(ENCODING);
            //设置加密算法，生成秘钥
            SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
            //选择加密
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            //根据待加密内容生成字节数组
            byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING));
            //返回base64字符串
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            Log.e("", "AES encrypt exception:" + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 解密
     *
     * @param content 待解密内容
     * @return
     */
    public static String decrypt(String content){
        if(TextUtils.isEmpty(content)){
            Log.e("", "AES decrypt: the content is null!");
            return null;
        }
        //判断秘钥是否为16位
        try {
            //对密码进行编码
            byte[] bytes = KEY.getBytes(ENCODING);
            //设置解密算法，生成秘钥
            SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
            //选择解密
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);

            //先进行Base64解码
            byte[] decodeBase64 = Base64.getDecoder().decode(content);

            //根据待解密内容进行解密
            byte[] decrypted = cipher.doFinal(decodeBase64);
            //将字节数组转成字符串
            return new String(decrypted, ENCODING);
        } catch (Exception e) {
            Log.e("", "AES decrypt exception:" + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * AES_CBC加密
     *
     * @param content 待加密内容
     * @param aesKey  密码
     * @return
     */
//    public static String encryptCBC(String content, String aesKey){
//        if(!TextUtils.isEmpty(content)){
//            Log.e("", "AES_CBC encrypt: the content is null!");
//            return null;
//        }
//        //判断秘钥是否为16位
//        if(!TextUtils.isEmpty(aesKey) && aesKey.length() == 16){
//            try {
//                //对密码进行编码
//                byte[] bytes = aesKey.getBytes(ENCODING);
//                //设置加密算法，生成秘钥
//                SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
//                // "算法/模式/补码方式"
//                Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
//                //偏移
//                IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING));
//                //选择加密
//                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
//                //根据待加密内容生成字节数组
//                byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING));
//                //返回16进制字符串
//
////                return Hex.decodeHex(content.toCharArray());
////                return DatatypeConverter.printHexBinary(encrypted);-------------------------------------------
//                //返回base64字符串
//                //return Base64Utils.encodeToString(encrypted);
//            } catch (Exception e) {
//                Log.e("", "AES_CBC encrypt exception:" + e.getMessage());
//                throw new RuntimeException(e);
//            }
//
//        }else {
//            Log.e("", "AES_CBC encrypt: the aesKey is null or error!");
//            return null;
//        }
//    }
    public static byte[] hex2Byte(String hex) {
        String[] parts = hex.split(" ");
        byte[] bytes = new byte[parts.length];
        for (int i = 0; i < parts.length; i++) {
            bytes[i] = (byte) Integer.parseInt(parts[i], 16);
        }
        return bytes;
    }


    /**
     * AES_CBC加密
     *
     * @param content 待加密内容
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encryptCBCNew(String content) {
        byte[] aesContent = content.getBytes(StandardCharsets.UTF_8);
        int len = aesContent.length;
        len = (16 - (len % 16)) + len;
        byte[] aesC = new byte[len];
        System.arraycopy(aesContent, 0, aesC, 0, aesContent.length);
        //判断秘钥是否为16位
        try {
            //设置加密算法，生成秘钥
            SecretKeySpec skeySpec = new SecretKeySpec(CBC_KEY, AES_ALGORITHM);
            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
            //偏移
            IvParameterSpec iv = new IvParameterSpec(CBC_IV);
            //选择加密
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            //根据待加密内容生成字节数组
            byte[] encrypted = cipher.doFinal(aesC);
            //返回16进制字符串
            //return DatatypeConverter.printHexBinary(encrypted);
            //返回base64字符串
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            Log.e("", "AES_CBC encrypt exception:" + e.getMessage());
            throw new RuntimeException(e);
        }


    }

    /**
     * AES_CBC解密
     *
     * @param content 待解密内容
     * @param aesKey  密码
     * @return
     */
    public static String decryptCBC(String content, String aesKey) {
        if (TextUtils.isEmpty(content)) {
            Log.e("", "AES_CBC decrypt: the content is null!");
            return null;
        }
        //判断秘钥是否为16位
        if (!TextUtils.isEmpty(aesKey) && aesKey.length() == 16) {
            try {
                //对密码进行编码
                byte[] bytes = aesKey.getBytes(ENCODING);
                //设置解密算法，生成秘钥
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
                //偏移
                IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING));
                // "算法/模式/补码方式"
//                Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
                Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
                //选择解密
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

                //先进行Hex解码
//                byte[] decodeBase64 = DatatypeConverter.parseHexBinary(content);
                byte[] decodeBase64 = Hex.decodeHex(content.toCharArray());
                //根据待解密内容进行解密
                byte[] decrypted = cipher.doFinal(decodeBase64);
                //将字节数组转成字符串
                return new String(decrypted, ENCODING);
            } catch (Exception e) {
                Log.e("", "AES_CBC decrypt exception:" + e.getMessage());
                throw new RuntimeException(e);
            }

        } else {
            Log.e("", "AES_CBC decrypt: the aesKey is null or error!");
            return null;
        }
    }

    /**
     * 解密
     * @param String src 解密字符串
     * @param String key 密钥
     * @return 解密后的字符串
     */
    public static String Decrypt(String src, String key) {
        try {
            // 判断Key是否正确
            if (key == null) {
                System.out.print("Key为空null");
                return null;
            }

            // 密钥补位
            int plus= 16-key.length();
            byte[] data = key.getBytes("utf-8");
            byte[] raw = new byte[16];
            byte[] plusbyte={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
            for(int i=0;i<16;i++)
            {
                if (data.length > i)
                    raw[i] = data[i];
                else
                    raw[i] = plusbyte[0];
            }

            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);

            //byte[] encrypted1 = new Base64().decode(src);//base64
//            byte[] encrypted1 = toByteArray(src);//十六进制

            byte[] encrypted1 = Hex.decodeHex(src.toCharArray());

            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,"utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    /**
     * 将byte[]转为各种进制的字符串
     * @param bytes byte[]
     * @param radix 可以转换进制的范围，从Character.MIN_RADIX到Character.MAX_RADIX，超出范围后变为10进制
     * @return 转换后的字符串
     */
    public static String binary(byte[] bytes, int radix){
        return new BigInteger(1, bytes).toString(radix);   // 这里的1代表正数
    }

    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString 16进制格式的字符串
     * @return 转换后的字节数组
     **/
    public static byte[] toByteArray(String hexString) {
        if (hexString.isEmpty())
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制，最多只会占用4位，转换成字节需要两个16进制的字符，高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }





    public static final String arrayToString(byte[] bytes) {
        StringBuffer buff = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            buff.append(bytes[i] + " ");
        }
        return buff.toString();
    }


    /**
     * 16进制字符串转换成byte数组
     */
    public static byte[] Hex2Bytes(String hexString) {
        byte[] arrB = hexString.getBytes();
        int iLen = arrB.length;
        byte[] arrOut = new byte[iLen / 2];
        String strTmp = null;
        for (int i = 0; i < iLen; i += 2) {
            strTmp = new String(arrB, i, 2);
            arrOut[(i / 2)] = ((byte) Integer.parseInt(strTmp, 16));
        }
        return arrOut;
    }


//    public static void main(String[] args) throws UnsupportedEncodingException {
//        // AES支持三种长度的密钥：128位、192位、256位。
//        // 代码中这种就是128位的加密密钥，16字节 * 8位/字节 = 128位。
//        String random = RandomStringUtils.random(16, "abcdefghijklmnopqrstuvwxyz1234567890");
//        System.out.println("随机key:" + random);
//        System.out.println();
//
//        System.out.println("---------加密---------");
//        String aesResult = encrypt("测试AES加密");
//        System.out.println("aes加密结果:" + aesResult);
//        System.out.println();
////
//        System.out.println("---------解密---------");
//        String decrypt = decrypt(aesResult);
//        System.out.println("aes解密结果:" + decrypt);
//        System.out.println();
//
//        System.out.println(arrayToString(Base64Utils.decodeFromString("tHMbSC5b9Gb9fLn2pFQ0ug==")));
//
//        byte[] key =  { 0x76, 0x49, (byte) 0xab, (byte) 0xac, (byte) 0x81, 0x19, (byte) 0xb2, 0x46, (byte) 0xce, (byte) 0xe9, (byte) 0x8e, (byte) 0x9b, 0x12, (byte) 0xe9, 0x19, 0x7d};
//        byte[] iv =  { 0x73, (byte) 0xbe, (byte) 0xd6, (byte) 0xb8, (byte) 0xe3, (byte) 0xc1, 0x74, 0x3b, 0x71, 0x16, (byte) 0xe6, (byte) 0x9e, 0x22, 0x22, (byte) 0x95, 0x16 };
//
//        byte[] data={(byte) 0xb2,0x30,0x05, (byte) 0x8d, (byte) 0xbe, (byte) 0xd2,0x1e,0x3b,0x54, (byte) 0xb9,0x74, (byte) 0x92,0x31, (byte) 0x9b,0x50, (byte) 0xaa};
//        System.out.println(arrayToString(data));
//
//        String aa = "012A5B5800EE8CBC0000000000000000";
//        byte[] a = Hex2Bytes(aa);
//        System.out.println(arrayToString(a));
////        System.out.println("--------AES_CBC加密解密---------");
//        String cbcResult = encryptCBCNew(aa);
//        System.out.println("aes_cbc加密结果:" + cbcResult);
////        System.out.println();
//
////        System.out.println("---------解密CBC---------");
////        String cbcDecrypt = decryptCBC(cbcResult, "1111111111111111");
////        System.out.println("aes解密结果:" + cbcDecrypt);
////        System.out.println();
//    }
}

